﻿/*
 * Jonathan
 * Created by: Jonathan Montiverdi
 * Date: 6/13/2012
 * License: http://jonathan.codeplex.com/license
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Awesomium.Core;
using Jonathan.Data;
using Monti.Docking;
using Monti.MVVM.Services;

namespace Jonathan.Logic
{
   /// <summary>
   /// Description of BookManagerViewModel.
   /// </summary>
   public class LibraryViewModel : DockItem, IDataViewerModel
   {
      #region Fields
      
      private IMain m_Main;
      private IOptions m_Options;
      
      private string m_Html;
      
      /// <summary>
      /// Event used to notify the item is closing.
      /// </summary>
      public event EventHandler ItemClosing;
      
      /// <summary>
      /// Event used to execute an html change request.
      /// </summary>
      public event HtmlChangeEventHandler HtmlChangeRequested;
      
      #endregion
      
      #region Setup
      
      /// <summary>
      /// Initializes a new book manager.
      /// </summary>
      public LibraryViewModel()
      {
         this.Title = "Library";
         this.ToolTip = "Manage options about the books Jonathan uses.";
         this.Html = this.BuildHtml ();
      }
      
      #endregion
      
      #region Properties
      
      /// <summary>
      /// Gets or Sets the main application.
      /// </summary>
      public IMain Main { get { return this.m_Main ?? (this.m_Main = ServiceManager.Resolve <IMain> ()); } }
      
      /// <summary>
      /// Gets the options of the application.
      /// </summary>
      public IOptions Options { get { return this.m_Options ?? (this.m_Options = ServiceManager.Resolve <IOptions> ()); } }
      
      /// <summary>
      /// Gets or Sets the html to display in the data viewer.
      /// </summary>
      public string Html
      {
         get { return this.m_Html; }
         set
         {
            if (this.m_Html != value)
            {
               this.m_Html = value;
               if (this.HtmlChangeRequested != null)
                  this.HtmlChangeRequested (new HtmlChangeEventArgs { TagId = "Html", Content = value });
               this.RaisePropertyChanged ("Html");
            }
         }
      }
      
      #endregion
      
      #region Methods
      
      /// <summary>
      /// Gets the list of a global javascript callbacks if any.
      /// </summary>
      public IDictionary <string, JSCallback> GetCallbacks ()
      {
         return new Dictionary <string, JSCallback> 
         {
            { "checked", this.ItemChecked },
            { "update", this.Update },
            { "download", this.Download }
         };
      }
      
      /// <summary>
      /// Occurs when an auto update items is checked.
      /// </summary>
      /// <param name="sender">WebControl</param>
      /// <param name="e">JSCallbackEventArgs</param>
      private void ItemChecked (object sender, JSCallbackEventArgs e)
      {
         if (e.Arguments.Length <= 0 ) return;
         var bookName = e.Arguments [0].ToString ();
         var book = this.Options.Books.FirstOrDefault (b => b.Name == bookName);
         if (book != null) book.UpdateAutomatically = !book.UpdateAutomatically;
         this.m_Html = this.BuildHtml ();
      }
      
      /// <summary>
      /// Occurs when an update button is clicked.
      /// </summary>
      /// <param name="sender">WebControl</param>
      /// <param name="e">JSCallbackEventArgs</param>
      private void Update (object sender, JSCallbackEventArgs e)
      {
         if (e.Arguments.Length <= 0 ) return;
         var bookName = e.Arguments [0].ToString ();
         var book = this.Options.Books.FirstOrDefault (b => b.Name == bookName);
         if (book != null)
            Downloader.AddToQueue (book.FileName, Common.DATA_DIR + book.FileName);
      }
      
      /// <summary>
      /// Occurs when a download button is clicked.
      /// </summary>
      /// <param name="sender">WebControl</param>
      /// <param name="e">JSCallbackEventArgs</param>
      private void Download (object sender, JSCallbackEventArgs e)
      {
         if (e.Arguments.Length <= 0 ) return;
         var bookName = e.Arguments [0].ToString ();
         var book = this.Options.AvailableBooks.FirstOrDefault (b => b.Name == bookName);
         if (book != null)
         {
            var download = Downloader.AddToQueue (book.FileName, Common.DATA_DIR + book.FileName);
            download.Completed += delegate
            {
               if (download.WasSuccessful)
               {
                  this.Options.Books.Add (book);
                  this.Options.RefreshBooks ();
                  this.Html = this.BuildHtml ();
               }
            };
         }
      }
      
      /// <summary>
      /// Builds the current Html string for the viewer.
      /// </summary>
      private string BuildHtml ()
      {
         var html = new StringBuilder ();
         html.AppendLine ("<html>");
         html.AppendLine (Common.GetHtmlHead ("Library"));
         html.AppendLine ("<body>");
         
         // TODO: Tool bar with options...
         // TODO: Scroll only table...
         html.AppendLine ("<table width=\"100%\" style=\"margin-bottom: 0px;\" class=\"table table-condensed\">");
         html.AppendLine ("<tr>");
         html.AppendLine ("<th style=\"width:100px;\">");
         html.AppendLine ("Download");
         html.AppendLine ("</th>");
         html.AppendLine ("<th style=\"width:50px;\">");
         html.AppendLine ("Auto<br />Update");
         html.AppendLine ("</th>");
         html.AppendLine ("<th>");
         html.AppendLine ("Book");
         html.AppendLine ("</th>");
         html.AppendLine ("</tr></table>");
         
         var bookCount = this.Options.Books.Count (b => b.FileExists);
         if (bookCount > 0)
         {
            // TODO: Only allow update if timestamp is different, or if main db download date is old...
            html.AppendLine ("<div style=\"margin-bottom: 0px;\" class=\"alert alert-info\">Books you have:</div>");
            html.AppendLine ("<table width=\"100%\" class=\"table table-striped\">");
            foreach (var book in this.Options.Books.Where (b => b.FileExists))
               this.AddBook (html, "Update", book);
            html.AppendLine ("</table>");
         }
         
         bookCount = this.Options.AvailableBooks.Count (b => !b.FileExists);
         if (bookCount > 0)
         {
            html.AppendLine ("<div style=\"margin-bottom: 0px;\" class=\"alert alert-info\">" +
                             "Books you should take a look at:</div>");
            html.AppendLine ("<table width=\"100%\" class=\"table table-striped\">");
            foreach (var book in this.Options.AvailableBooks.Where (b => !b.FileExists))
               this.AddBook (html, "Download", book);
            html.AppendLine ("</table>");
         }
         
         html.AppendLine ("</body>");
         html.AppendLine ("</html>");
         return html.ToString ();
      }
      
      /// <summary>
      /// Adds a book to the table.
      /// </summary>
      /// <param name="html">Html to add book row to.</param>
      /// <param name="action">Update or Download.</param>
      /// <param name="book">Book we are updating or downloading.</param>
      private void AddBook (StringBuilder html, string action, Book book)
      {
         html.AppendLine ("<tr>");
         html.AppendLine ("<td align=\"left\" style=\"width:100px;\">");
         if (action == "Update")
         {
            html.AppendLine (string.Format ("<button style=\"width:100px;\" class=\"btn btn-success\" onclick=\"glObj.update ('{0}')\">" +
                                            "<i class=\"icon-download icon-white\"></i> {1}</button>", book.Name, action));
         }
         else
         {
            html.AppendLine (string.Format ("<button style=\"width:100px;\" class=\"btn btn-info\" onclick=\"glObj.download ('{0}')\">" +
                                            "<i class=\"icon-download icon-white\"></i> {1}</button>", book.Name, action));
         }
         html.AppendLine ("</td>");
         
         html.AppendLine ("<td style=\"width:50px;\">");
         if (action == "Update")
         {
            html.AppendLine ("<label class=\"checkbox\">");
            html.AppendLine (string.Format ("<input type=\"checkbox\" onclick=\"glObj.checked ('{1}')\"{0}> ",
                                            book.UpdateAutomatically ? " checked" : string.Empty, book.Name.Replace ("'", "\\'")));
            html.AppendLine ("</label>");
         }
         else
            html.AppendLine ("&nbsp;");
         html.AppendLine ("</td>");
         html.AppendLine ("<td>");
         html.AppendLine (book.Name);
         html.AppendLine ("</td>");
         html.AppendLine ("</tr>");
      }
      
      /// <summary>
      /// Opens the given link.
      /// </summary>
      /// <param name="linkToOpen">Link to data to open.</param>
      public void Open (string linkToOpen)
      {
         var link = new Link (linkToOpen);
         if (link.FullLink.StartsWith ("Download|"))
         {
            var book = this.Options.AvailableBooks.First (b => b.Name.Equals (link.FullLink.Substring (9),
                                                                              StringComparison.CurrentCultureIgnoreCase));
            var download = Downloader.AddToQueue (book.FileName, Common.DATA_DIR + book.FileName);
            download.Completed += delegate
            {
               if (download.WasSuccessful)
               {
                  this.Options.Books.Add (book);
                  this.Html = this.BuildHtml ();
                  this.Options.RefreshBooks ();
               }
            };
         }
         else if (link.FullLink.StartsWith ("Update|"))
         {
            var book = this.Options.Books.First (b => b.Name.Equals (link.FullLink.Substring (7),
                                                                     StringComparison.CurrentCultureIgnoreCase));
            Downloader.AddToQueue (book.FileName, Common.DATA_DIR + book.FileName);
         }
      }
      
      /// <summary>
      /// Occurs when the tab is closing.
      /// </summary>
      /// <returns>True if ok to close, otherwise false.</returns>
      public override bool Closing ()
      {
         if (this.ItemClosing != null)
            this.ItemClosing (this, EventArgs.Empty);
         return true;
      }
      
      #endregion
   }
}
